package com.lxw.redis.study.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Range;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class BitmapService {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    // 设置指定位置的位值
    public void setBit(String key, long offset, boolean value) {
        redisTemplate.opsForValue().setBit(key, offset, value);
    }

    // 获取指定位置的位值
    public Boolean getBit(String key, long offset) {
        return redisTemplate.opsForValue().getBit(key, offset);
    }

    // 统计指定范围内的位值为 true 的个数
    public Long bitCount(String key) {
        return redisTemplate.execute((RedisCallback<Long>) connection -> connection.bitCount(key.getBytes()));
    }

    public Long bitCount(String key, long start, long end) {
        return redisTemplate.execute((RedisCallback<Long>) connection -> connection.bitCount(key.getBytes(), start, end));
    }

    // 首签时间
    public Long bitPos(String key, boolean bit) {
        return redisTemplate.execute((RedisCallback<Long>) connection -> connection.bitPos(key.getBytes(), bit));
    }

    public Long bitPos(String key, boolean bit, Long start, Long end) {
        Range<Long> range = Range.closed(start, end);
        return redisTemplate.execute((RedisCallback<Long>) connection -> connection.bitPos(key.getBytes(), bit, range));
    }

    // 连续签到/累计签到
    public Long bitOp(RedisStringCommands.BitOperation op, String destination, String... keys) {
        byte[][] keyBytes = new byte[keys.length][];
        for (int i = 0; i < keys.length; i++) {
            keyBytes[i] = keys[i].getBytes();
        }
        return redisTemplate.execute((RedisCallback<Long>) connection -> connection.bitOp(op, destination.getBytes(), keyBytes));
    }

    public List<Integer> members(String key) {
        String value = redisTemplate.opsForValue().get(key);
        List<Integer> list = new ArrayList();
        for (byte b : value.getBytes()) {
            for (int i = 7; i >= 0; i--) {
                list.add((b >> i) & 1);
            }
        }
        List<Integer> result = new ArrayList();
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i) == 1) {
                result.add(i);
            }
        }
        return result;
    }
}


